动画实现更简单,Navigation Compose 帮您忙
仅使用 Compose 1.0.0 中稳定的动画 API 开始对 Compose 1.0.0 中存在的实验性动画 API 提供支持 构建在 Compose 1.1.0 及更高版本中面向未来的动画 API (共享元素过渡)
Navigation Compose
https://developer.android.google.cn/jetpack/compose/navigation
Compose 💚 动画
实验性 API 和语义化版本控制
严格的语义化版本控制
https://semver.org/AndroidX 版本页面
https://developer.android.google.cn/jetpack/androidx/versions
使 Navigation 2.4 稳定
这种向前兼容性要求意味着 Navigation Compose 2.4.0 的任何代码只能依赖于稳定的 Compose 动画 API。这也是我们在 Navigation 2.4.0-alpha05 中增加交叉淡入淡出支持的方式——在 Compose 的世界中,您应该首先消除生硬的页面跳转。
Navigation 2.4.0-alpha05
https://developer.android.google.cn/jetpack/androidx/releases/navigation#2.4.0-alpha05
这种仅使用稳定 Compose 动画 API 的限制意味着 Navigation 2.4 不能直接使用 AnimatedContent 之类的 API,您不能将它们直接作为 Navigation 2.4 的一部分来使用以实现那种丰富的动画控制。但是,Navigation 的可扩展性意味着底层框架已经被构建好了并且是可用的。
AnimatedContent
https://developer.android.google.cn/reference/kotlin/androidx/compose/animation/package-summary#AnimatedContent(kotlin.Any,androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function2)
介绍: Accompanist 导航动画!
对于目的地之间动画切换的支持是我们能发布 Accompanist Navigation Animation 的原因,它基于最近发布的 Navigation 2.4.0-alpha06。导航动画库为您一直在使用的 Navigation Compose API 提供一套带动画的版本:
使用 rememberAnimatedNavController() 替换 rememberNavController() 使用 AnimatedNavHost 替换 NavHost 使用 import com.google.accompanist.navigation.animation.navigation 替换 import androidx.navigation.compose.navigation 使用 import com.google.accompanist.navigation.animation.composable 替换 import androidx.navigation.compose.composable
Accompanist Navigation Animation
https://google.github.io/accompanist/navigation-animation/Navigation 2.4.0-alpha06
https://developer.android.google.cn/jetpack/androidx/releases/navigation#2.4.0-alpha06
乍一看,您应用的外观没有发生改变——默认动画仍然是 fadeIn 和 fadeOut 类型,与 Navigation 2.4 中所提供的淡入淡出类型相同。然而,您将获得一项重要的新功能——能够配置这些动画并在页面之间替换您自己的过渡动画。
每个 composable 目的地都有四个新参数可以设置:
enterTransition: 指定当您使用 navigate() 导航至该目的地时执行的动画。 exitTransition: 指定当您通过导航至另一个目的地的方式离开该目的地时执行的动画。 popEnterTransition: 指定当该目的地在经过调用 popBackStack() 后重新入场时执行的动画。默认为 enterTransition。 popExitTransition: 指定当该目的地在以弹出返回栈的方式离开屏幕时执行的动画。默认为 exitTransition。
在每种情况下,这些参数都具有相同的格式:
enterTransition: (
(
initial: NavBackStackEntry,
target: NavBackStackEntry
) -> EnterTransition?
)? = null,
每个参数都接收一个 lambda。该 lambda 有两个 NavBackStackEntry 类型的参数,分别表示您来自何处 (initial) 和您要去往何处 (target)。以 enterTransition 为例,将要进入的目的地为 target —— 也就是将要启用 enterTransition 的目的地。而 exitTransition 则相反: initial 为将要执行退出动画的目的地。
这使得您可以像这样编写目的地:
composable(
"profile/{id}",
enterTransition = { _, _ ->
// 让我们写一个很长的淡入
fadeIn(animationSpec = tween(2000)
}
) {
// 像往常一样添加内容
}
或者,根据您来自/去往何处来控制您的动画:
composable(
"friendList"
exitTransition = { _, target ->
when (target.destination.route) {
"profile/{id}" -> ExitTransition.fadeOut(
animationSpec = tween(2000)
) // 慢慢地淡出
else -> null // 使用默认值
}
}
) {
// 像往常一样添加内容
}
composable(
"profile/{id}",
enterTransition = { initial, _ ->
when (initial.destination.route) {
"friendList" -> slideInVertically(
initialOffsetY = { 1800 }
) // 滑入 profile 页面
else -> null // 使用默认值
}
) {
// 像往常一样添加内容
}
navigation(
startDestination = "ask_username"
route = "login"
enterTransition = { initial, _ ->
// 检查上一个页面是否在登录子图中
if (initial.destination.hierarchy.any { it.route == "login" }) {
slideInHorizontally(initialOffsetX = { 1000 }
} else
null // 使用默认值
}
exitTransition = { _, target ->
// 检查新的页面是否在登录子图中
if (target.destination.hierarchy.any { it.route == "login" }) {
slideOutHorizontally(targetOffsetX = { -1000 }
} else
null // 使用默认值
}
popEnterTransition = { initial, _ ->
// 检查上一个页面是否在登录子图中
if (initial.destination.hierarchy.any { it.route == "login" }) {
// 请注意我们在 pop 操作时从相反的方向做动画
slideInHorizontally(initialOffsetX = { -1000 }
} else
null // 使用默认值
}
popExitTransition = { _, target ->
// 检查新的页面是否在登录子图中
if (target.destination.hierarchy.any { it.route == "login" }) {
// 请注意我们在 pop 操作时从相反的方向做动画
slideOutHorizontally(targetOffsetX = { 1000 }
} else
null // 使用默认值
}
) {
composable("ask_username") {
// 添加内容
}
composable("ask_password") {
// 添加内容
}
composable("register") {
// 添加内容
}
}
请注意我们使用 hierarchy 扩展方法来判断某个目的地是否属于登录子图的一部分——这样一来,我们进入登录子图和离开登录子图的过渡动画将使用默认值 (或者您在更高一级设置的任何过渡动画)。
hierarchy 扩展方法
https://developer.android.google.cn/reference/kotlin/androidx/navigation/NavDestination#(androidx.navigation.NavDestination).hierarchy()
Accompanist 充当了 Jetpack 库的助推器,使得我们可以在 Compose 1.1 的开发过程中立即获得实验性功能。
添加 Accompanist 导航动画依赖:
https://google.github.io/accompanist/navigation-animation/
implementation
"com.google.accompanist:accompanist-navigation-animation:0.16.0"
Navigation Compose 和动画的未来
支持共享元素过渡
Compose 路线图
https://developer.android.google.cn/jetpack/androidx/compose-roadmap
我们对于 Navigation 2.5 的目标是将 Compose 1.1 的所有优点带到 Navigation Compose 中。这意味着当动画 API 解除实验性状态时,我们可以直接将其带到 Navigation Compose。这也意味着我们可以构建支持共享元素过渡的 API。
这还意味着 Accompanist 导航动画应该被视为一种临时措施: 一旦 Navigation Compose 自身提供了相同级别的动画 API (根据您的反馈量身定做),您将可以直接依赖于它并且可以完全移除 Accompanist 导航动画库。
继续前进
平衡稳定性以及我们作为 Jetpack 库对自己提出的向前和向后兼容性要求,并具有快速交付功能的能力,这并不像我们想象的那么简单。随着 Jetpack Compose 不断发展,对不断超前的需求而言,Accompanist 是一个巨大的福音。我要感谢 Chris Banes 和所有投入时间在 Accompanist 上的开发者、Compose 背后的整个团队,以及大家帮助塑造 Android 开发的未来。
Chris Banes
https://chrisbanes.medium.com/
Accompanist Navigation Material
https://google.github.io/accompanist/navigation-material/
介绍 Navigation-Material 🧭🎨️
https://jossiwolf.medium.com/introducing-navigation-material-%EF%B8%8F-a19ed5cc33fd
欢迎您通过下方二维码向我们提交反馈,或分享您喜欢的内容、发现的问题。您的反馈对我们非常重要,感谢您的支持!
推荐阅读